理解Window和WindowManager

本文详细介绍了Window在Android系统中的概念,包括Window与WindowManager的使用,Window的内部工作机制,如添加、删除和更新过程。此外,还探讨了Activity、Dialog和Toast创建Window的具体步骤,帮助读者深入理解Android窗口管理。
摘要由CSDN通过智能技术生成


一、Window简介


(1)Window表示一个窗口的概念,一般用不到,当在某些特殊的时候我们需要在桌面上显示一个类似悬浮窗的东西就需要Window来实现。
(2)Window是一个抽象类,它的具体实现是PhoneWindow。
(3)创建一个Window只需要通过WindowManager即可完成。
(4)WindowManager是外界访问Window的入口,Window的具体实现是WindowManagerService,WindowManager和WindowManagerService的交互是一个IPC过程。
(5)Android中所有的视图都是通过Window呈现的,不管是Activity、Dialog还是Toast,他们的视图实际上都是附加在Window上的,因此Window实际是View的直接管理者。


二、Window和WindowManager


1、使用WindowManager添加一个Window


为了分析Window的工作机制,我们需要先了解如何使用WindowManager添加一个Window:
/*
        	 * 下面的代码演示了通过WindowManager添加Window的过程:
        	 * (1)创建Button按钮。
        	 * (2)为Button设置文字内容。
        	 * (3)创建一个WindowManager.LayoutParams的参数,设置Button的宽高之类的。
        	 * (4)为WindowManager.LayoutParams设置Flags参数。
        	 * (5)为WindowManager.LayoutParams设置type参数。
        	 * (6、7、8)为WindowManager.LayoutParams设置中心点、坐标位置。
        	 * (9)给Button设置触摸事件。
        	 * (10)将Button按照WindowManager.LayoutParams参数用WindowManager添加View即可。
        	 * */
            mFloatingButton = new Button(this);
            mFloatingButton.setText("click me");
            mLayoutParams = new WindowManager.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
                    PixelFormat.TRANSPARENT);
            mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | LayoutParams.FLAG_NOT_FOCUSABLE
                    | LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            mLayoutParams.x = 100;
            mLayoutParams.y = 300;
            mFloatingButton.setOnTouchListener(this);
            mWindowManager.addView(mFloatingButton, mLayoutParams);
(1)Flags参数表示Window的属性,它有很多选项,通过这些选项可以控制Window的显示特性,下面介绍几个主要的:
FLAG_NOT_FOCUSABLE:表示Window不需要获取焦点,也不需要接收各种输入事件,此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的Window。
FLAG_NOT_TOUCH_MODAL:在此模式下,系统会将当前Window区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理。 一般来说都需要开启此标记,否则其他Window将无法收到单击事件。
 FLAG_SHOW_WHEN_LOCKED:此模式可以让Window显示在锁屏的界面上。
(2)Type参数表示Window的类型,一共有三种类型:
应用Window(层级范围1~99):对应着一个Activity。
子Window(层级范围1000~1999):不能单独存在,它需要附属在特定的父Window之中,比如常见的Dialog就是一个子Window。
系统Window(层级范围2000~2999):是需要声明权限才能创建的Window,比如Toast和系统状态栏都属于系统Window。
 层级范围对应这WindowManager.LayoutParams的type参数,层级大的会覆盖在层级小的Window上面。所以系统层级是最大的,系统层级一般选用TYPE_SYSTEM_ERROR或者TYPE_SYSTEM_OVERLAY。 还有哦,系统层级需要声明权限:不然会报错:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
(3)将Button按照WindowManager.LayoutParams参数用WindowManager添加View即可。 所以这个Button就作为一个新的Window了。
 !!!!!Window并不是实际存在的,它以View的形式存在。!!!!!!
WindowManager所提供的功能很简单,常用的只有三个方法:即添加View、更新View和删除View。这三个方法定义在ViewManager中,ViewManager是一个接口,而WindowManager正是继承了ViewManager。
package android.view;

/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
 * (1)ViewManager这个接口是由WindowManager来继承的,WindowManager可以用来创建Window。
 * ViewManager这里面提供了三个方法,分别是添加、更新和删除View。
 * (2)WindowManagerImpl继承自WindowManager,
 * 而WindowManager又是继承自ViewManager,
 * addView、updateViewLayout、removeView都是来自ViewManager的。
 * 所以在WindowManagerImpl具体实现了这三个方法。

继承关系:
ViewManager  -->> WindowManager(继承自ViewManager) -->> WindowManagerImpl(继承自WindowManager) -->> WindowManagerGlobal(WindowManagerImpl内部的一个对象) 
在ViewManager中有三个方法:addView、updateViewLayout、removeView。它们最终是在WindowManagerGlobal中具体实现的。

2、下面这个例子中的onTouch实现了拖动的Window效果

package com.ryg.chapter_8;

import com.ryg.chapter_8.R;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;

public class TestActivity extends Activity implements OnTouchListener {

    private static final String TAG = "TestActivity";

    private Button mCreateWindowButton;

    private Button mFloatingButton;
    private WindowManager.LayoutParams mLayoutParams;
    private WindowManager mWindowManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        initView();
    }

    private void initView() {
        mCreateWindowButton = (Button) findViewById(R.id.button1);
        mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    }

    public void onButtonClick(View v) {
        if (v == mCreateWindowButton) {
        	/*
        	 * 下面的代码演示了通过WindowManager添加Window的过程:
        	 * */
            mFloatingButton = new Button(this);
            mFloatingButton.setText("click me");
            mLayoutParams = new WindowManager.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
                    PixelFormat.TRANSPARENT);
            mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | LayoutParams.FLAG_NOT_FOCUSABLE
                    | LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            mLayoutParams.x = 100;
            mLayoutParams.y = 300;
            mFloatingButton.setOnTouchListener(this);
            mWindowManager.addView(mFloatingButton, mLayoutParams);
        }
    }

    @SuppressLint("ClickableViewAccessibility") @Override
    public boolean onTouch(View v, MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            break;
        }
        case MotionEvent.ACTION_MOVE: {
        	/*
        	 * 如果想要实现可以拖动的Window效果,
        	 * 只需要根据手指的位置来设定LayoutParams中的x和y的值即可改变Window的位置。
        	 * */
            int x = (int) event.getX();
            int y = (int) event.getY();
            mLayoutParams.x = rawX;
            mLayoutParams.y = rawY;
            mWindowManager.updateViewLayout(mFloatingButton, mLayoutParams);
            break;
        }
        case MotionEvent.ACTION_UP: {
            break;
        }
        default:
            break;
        }

        return false;
    }

    @Override
    protected void onDestroy() {
        try {
            mWindowManager.removeView(mFloatingButton);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
}



三、Window的内部机制


1、综述


Window是一个抽象概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此Window并不是实际存在的,它是以View的形式存在。这点从WindowManager的定义也可以看出,它提供的三个接口方法addView、updateViewLayout、removeView都是针对View的,这说明View才是WindowManager存在的实体。在实际使用中无法直接访问Window,对Window的访问必须通过WindowManager。

ViewManager  -->> WindowManager(继承自ViewManager) -->> WindowManagerImpl(继承自WindowManager) -->> WindowManagerGlobal(WindowManagerImpl内部的一个对象)  -->> ViewRooImpl

2、Window的添加过程


(1)可以发现WindowManagerImpl并没有实现WindowManager的三大操作,而是全部交给WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例。就是说WindowManagerImpl将所有的操作全部委托给WindowManagerGlobal来实现。这是一种桥接模式。
(2)WindowManagerImpl.java文件:
package android.view;

/**
 * Provides low-level communication with the system window manager for
 * operations that are bound to a particular context, display or parent window.
 * Instances of this object are sensitive to the compatibility info associated
 * with the running application.
 *
 * This object implements the {@link ViewManager} interface,
 * allowing you to add any View subclass as a top-level window on the screen.
 * Additional window manager specific layout parameters are defined for
 * control over how windows are displayed.  It also implements the {@link WindowManager}
 * interface, allowing you to control the displays attached to the device.
 * 
 * <p>Applications will not normally use WindowManager directly, instead relying
 * on the higher-level facilities in {@link android.app.Activity} and
 * {@link android.app.Dialog}.
 * 
 * <p>Even for low-level window manager access, it is almost never correct to use
 * this class.  For example, {@link android.app.Activity#getWindowManager}
 * provides a window manager for adding windows that are associated with that
 * activity -- the window manager will not normally allow you to add arbitrary
 * windows that are not associated with an activity.
 *
 * @see WindowManager
 * @see WindowManagerGlobal
 * @hide
 */
public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;

    public WindowManagerImpl(Display display) {
        this(display, null);
    }

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

    public WindowManagerImpl createPresentationWindowManager(Display display) {
        return new WindowManagerImpl(display, mParentWindow);
    }

    /*
     * Window的添加,即View的添加:
     * */
    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
    	/*
    	 * 这里变成了四个参数:
    	 * */ 
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        mGlobal.updateViewLayout(view, params);
    }

    /*
     * Window的删除,即View的删除:
     * */
    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

    @Override
    public Display getDefaultDisplay() {
        return mDisplay;
    }
}
(3)WindowManagerGlobal.java文件中的addView方法首先检查参数是否合法,如果是子Window那么还需要调整一些布局参数:
if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        /*
         * 如果是子Window,那么还需要调整一些布局参数:
         * */
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        }
(4ÿ
  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值